package gov.nist.ssd.swqb.core.search;

import static gov.nist.ssd.swqb.config.DebugMode.dClassName;
import static gov.nist.ssd.swqb.config.DebugMode.dMethodName;
import static gov.nist.ssd.swqb.config.DebugMode.dRequestGoal;
import static gov.nist.ssd.swqb.config.DebugMode.dSparqlText;
import static gov.nist.ssd.swqb.config.DebugMode.debugModeIsOn;
import static gov.nist.ssd.swqb.config.DebugMode.printSparqlDebugInformations;

import java.util.Iterator;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;

abstract class AbstractAskSearch extends AbstractSearch {

  protected AbstractAskSearch(SearchText searchText, Model model, int requestsSize,
      VarName varName, RequestPattern searchPattern) {
    super(searchText, model, requestsSize, varName, searchPattern);
  }

  @Override
  public Iterator<RDFNode> iterator() {
    return new Iterator<RDFNode>() {

      private RDFNode value = null;
      
      public Iterator<RDFNode> init() {
   
        if(debugModeIsOn()) {
          printSparqlDebugInformations(
              dClassName(getOuter().getClass().toString()+"$1"),
              dMethodName("init"),
              dRequestGoal("ask whether or not this node exists"),
              dSparqlText(getBaseQuery()));
        }
             
        Query query = QueryFactory.create(getBaseQuery(), Syntax.syntaxARQ);
        QueryExecution qexec = QueryExecutionFactory.create(query, getModel());
        if(qexec.execAsk()) {
          value = getNode();
        } else {
          value = null;
        }
        
        return this;
      }
      
      @Override
      public boolean hasNext() {
        return value!=null;
      }

      @Override
      public RDFNode next() {
        if(hasNext()) {
          RDFNode res = value;
          value = null;
          return res;
        } else {
          throw new UnsupportedOperationException();
        }
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }
      
    }.init();
  }

  /**
   * Has to return RDFNode we are looking for.
   * This will be called only if the model contains this node so don't worry
   * too much about possible node creation in the model when you implement this.
   * @return
   */
  public abstract RDFNode getNode();
  
}
